/*!
    \copyright  Copyright (c) 2024 Qualcomm Technologies International, Ltd.
    \version    %version
    \file
    \ingroup    adk_test_common
    \brief      SPP Handover Interfaces for Earbud application
*/
#ifdef INCLUDE_SPPS_LOOPBACK_TEST
#include "spps_test_private_data.h"
#include <marshal.h>
#include "handover_if.h"
#include "spps_test_marshal_desc.h"
#include <logging.h>

/*! \brief Handover Veto interface, But in case of SPP Loopback we dont Veto hand */
static bool sppTest_Veto(void);
/*! \brief Handover Marshal interface to marshall SPP Loopback application data to new primary */
static bool sppTest_Marshal(const tp_bdaddr *addr, uint8 *buffer, uint16 buffer_size, uint16 *written);
/*! \brief Handover UnMarshal interface to unmarshall SPP Loopback application data to new primary */
static bool sppTest_Unmarshal(const tp_bdaddr *addr, const uint8 *buffer, uint16 buffer_size, uint16 *consumed);
/*! \brief Handover Commit interface to reconfigure the streams on new primary */
static void sppTest_Commit(const tp_bdaddr *tp_bd_addr, const bool role);
/*! \brief Handover Complete interface,No action from SPP Loopback application */
static void sppTest_Complete(const bool role);
/*! \brief Handover Abort interface,No action from SPP Loopback application */
static void sppTest_Abort(void);


/*! Use this flag to clean unmarshalled data, if any, during handover abort phase */
static bool spp_test_is_unmarshalled = FALSE;

/*! \brief SPP Loopback application handover interfaces for earbud app */
const handover_interface spp_test_handover_if =
        MAKE_BREDR_HANDOVER_IF(&sppTest_Veto,
                             &sppTest_Marshal,
                             &sppTest_Unmarshal,
                             &sppTest_Commit,
                             &sppTest_Complete,
                             &sppTest_Abort);

static bool sppTest_Veto(void)
{
    /* Do not Veto Handover */
    return FALSE;
}

static void sppTest_Complete(const bool is_primary)
{
    UNUSED(is_primary);
    DEBUG_LOG_INFO("sppTest_HandoverComplete, No Actions");
    /* mark complete of unmarshalled data*/
    spp_test_is_unmarshalled = FALSE;
}

static void sppTest_Abort(void)
{
    DEBUG_LOG_INFO("sppTest_Abort ");
    if( spp_test_is_unmarshalled)
    {
        for(uint8 instance_id = 0; instance_id < spp_max_instances; instance_id++)
        {
            sppTest_SetSppConnIdForIndex(instance_id, SPP_INVALID_CONN_ID);
        }
        spp_test_is_unmarshalled = FALSE;
    }
}

/*! \brief Find the battery client configuration and marshal if any exists */
static bool sppTest_Marshal(const tp_bdaddr *tp_bd_addr,
                                      uint8 *buf,
                                      uint16 length,
                                      uint16 *written)
{
    UNUSED(tp_bd_addr);

    spp_test_marshal_data_t obj;
    bool marshalled;

    for(int instance_id = 0; instance_id < spp_max_instances; instance_id++)
    {

        if(sppTest_IsInstanceValid(instance_id))
        {
            obj.spp_connection_id[instance_id] = sppTest_GetSppConnIdFromIndex(instance_id);
            DEBUG_LOG("sppTest_Marshal: Marshalling SPP instance data instande->%d  connid --> %d",instance_id,obj.spp_connection_id[instance_id]);
        }
    }
    marshaller_t marshaller = MarshalInit(mtd_spp_test, SPP_TEST_MARSHAL_OBJ_TYPE_COUNT);
    MarshalSetBuffer(marshaller, (void*)buf, length);
    marshalled = Marshal(marshaller, &obj, MARSHAL_TYPE(spp_test_marshal_data_t));
    *written = marshalled? MarshalProduced(marshaller): 0;
    MarshalDestroy(marshaller, FALSE);
    DEBUG_LOG("sppTest_Marshal: Marshalling SPP instance data->%d", marshalled);

    return marshalled;
}

static bool sppTest_Unmarshal(const tp_bdaddr *tp_bd_addr,
                                                 const uint8 *buf,
                                                 uint16 length,
                                                 uint16 *consumed)
{
    UNUSED(tp_bd_addr);

    marshal_type_t unmarshalled_type;
    spp_test_marshal_data_t *data = NULL;
    unmarshaller_t unmarshaller = UnmarshalInit(mtd_spp_test, SPP_TEST_MARSHAL_OBJ_TYPE_COUNT);

    UnmarshalSetBuffer(unmarshaller, (void *)buf, length);

    DEBUG_LOG("sppTest_Unmarshal");

    if (Unmarshal(unmarshaller, (void **)&data, &unmarshalled_type))
    {
        PanicFalse(unmarshalled_type == MARSHAL_TYPE(spp_test_marshal_data_t));
        PanicNull(data);

        for(uint8 instance_id = 0; instance_id < spp_max_instances; instance_id++)
        {
            sppTest_SetSppConnIdForIndex(instance_id, data->spp_connection_id[instance_id]);
        }

        spp_test_is_unmarshalled = TRUE;
        *consumed = UnmarshalConsumed(unmarshaller);
        UnmarshalDestroy(unmarshaller, TRUE);
        return TRUE;
    }
    else
    {
        *consumed = 0;
        DEBUG_LOG("sppTest_Unmarshal: failed unmarshal");
        UnmarshalDestroy(unmarshaller, TRUE);
        return FALSE;
    }
}

static void sppTest_Commit(const tp_bdaddr *tp_bd_addr, const bool is_primary)
{
    UNUSED(tp_bd_addr);

    if (is_primary)
    {
        for(int instance_id = 0; instance_id < spp_max_instances; instance_id++)
        {
            if(sppTest_IsInstanceValid(instance_id))
            {
                DEBUG_LOG_INFO("sppTest_Commit, rfcomm restore success");
                sppTest_ConfigureSppStreams(instance_id);

            }
            else
            {
               DEBUG_LOG_INFO("sppTest_Commit.Instance Not Available");
            }
        }
    }
}
#endif /* INCLUDE_SPPS_LOOPBACK_TEST */
